#include <brpc/server.h>
#include <butil/logging.h>

#include "asr.hpp"     // 语音识别模块封装
#include "etcd.hpp"    // 服务注册模块封装
#include "logger.hpp"  // 日志模块封装
#include "speech.pb.h" // protobuf框架代码

class SpeechServiceImpl : SpeechService
{
public:
    SpeechServiceImpl(const ASRClient::ptr &asr_client)
        : _asr_client(asr_client) {}
    ~SpeechServiceImpl() {}
    // 控制器 请求 相应 运行
    void SpeechRecognition(google::protobuf::RpcController *controller,
                           const SpeechRecognitionReq *request,
                           SpeechRecognitionRsp *response,
                           google::protobuf::Closure *done)
    {
        LOG.DEBUG("收到语音转文字请求！");
        // rpc服务启动
        brpc::ClosureGuard rpc_guard(done);
        // 取出请求中的语音数据
        std::string err;
        // 调用语音sdk模块进行语音识别，得到响应
        std::string ret = _asr_client->recognize(request->speech_content(), err);
        if (ret.empty())
        {
            LOG_ERROR("{} 语音识别失败！", request->request_id());
            response->set_request_id(request->request_id());
            response->set_success(false);
            response->set_errmsg("语音识别失败:" + err);
            return;
        }
        // 组织相应
        response->set_request_id(request->request_id());
        response->set_success(true);
        response->set_recognition_result(res);
    }

private:
    ASRClient::ptr _asr_client;
}

// rpc服务器搭建
class serverspeech
{
public:
    serverspeech(const ASEClient::ptr &asr_client,
                 const Registry::ptr &reg_client,
                 std::shared_ptr<brpc::Server> &rpc_server)
        : _asr_client(asr_client), _reg_client(reg_client), _rpc_server(rpc_server)
    {}
    ~serverspeech() {}

private:
    ASRClient::ptr _asr_client;
    Registry::ptr _reg_client;
    std::shared_ptr<brpc::Server> _rpc_server;
}
// 使用建造者模式
class SpeechServerBuilder
{
public:
    // 构造语音识别客户端对象
    void make_asr_client(const std::string &app_id,
                         const std::string &api_key,
                         const std::string &secret_key)
    {
        _asr_client = std::make_shared<ASRClient>(app_id, api_key, secret_key);
    }
    // 用于构造服务注册客户端对象
    void make_reg_object(const std::string &reg_host,
                         const std::string &service_name,
                         const std::string &access_host)
    {
        // 主机名
        _reg_client = std::make_shared<Registry>(reg_host);
        // 注册ip
        _reg_client->registry(service_name, access_host);
    }
    // 构造RPC服务器对象
    void make_rpc_server(uint16_t port, int32_t timeout, uint8_t num_threads)
    {
        // 语音识别未构造
        if (!_asr_client)
        {
            LOG_ERROR("还未初始化语音识别模块！");
            abort();
        }
        // rpc服务器
        rpc_server = std::make_shared<brpc::Server>();
        SpeechServiceImpl *speech_service = new SpeechServiceImpl(_asr_client);
        // 添加服务
        int ret = _rpc_server->AddService(speech_service, brpc::ServiceOwnership::SERVER_OWNS_SERVICE);
        if (ret == -1)
        {
            LOG_ERROR("添加Rpc服务失败！");
            abort();
        }
        // 启动服务器
        brpc::ServerOptions options;
        // 超时时间
        options.idle_timeout_sec = timeout;
        // 线程数
        options.num_threads = num_threads;
        // 开始
        ret = _rpc_server->Start(port, &options);
        if (ret == -1)
        {
            LOG_ERROR("服务启动失败！");
            abort();
        }
    }
    SpeechServer::ptr build()
    {
        // 未初始化语音识别
        if (!_asr_client)
        {
            LOG_ERROR("还未初始化语音识别模块！");
            about();
        }
        // 未初始化服务器注册
        if (!_reg_client)
        {
            LOG_ERROR("还未初始化服务注册模块！");
            abort();
        }
        // 未初始化rpc服务器
        if (!_rpc_server)
        {
            LOG_ERROR("还未初始化RPC服务器模块！");
            abort();
        }
        // 服务器
        SpeechServer::ptr server = std::make_shared<SpeechServer>(
            _asr_client, _reg_client, _rpc_server);
        return server;
    }

private:
    ASRClient::ptr _asr_client;
    Registry::ptr _reg_client;
    std::shared_ptr<brpc::Server> _rpc_server;
}
